package com.zhuqi;

import org.activiti.engine.*;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricActivityInstanceQuery;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.commons.io.IOUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.List;

/**
 * @author : ZhuQi
 * @version : 时间:2022/3/2 16:34 版本:
 * test(): 创建流程引擎
 * test02(): 部署一个流程
 * test03(): 启动一个流程
 * test04(): 查询流程
 * test05(): 任务流程处理
 * test06(): 查询流程定义
 * test07(): 删除流程
 * test08(): 资源文件下载
 * test09(): 测试查询历史流程实例
 */
public class ActivitiTestDemo01 {

    public static void main(String[] args) throws Exception {

        // 测试-部署一个流程
        // test02();

        // 测试-启动一个流程
        // test03();

        // 测试-查询任务
        // test04();

        // 测试-处理流程任务
        // test05();

        // 测试-查询流程定义信息
        // test06();

        // 测试-删除流程
        // test07();

        // 测试-资源文件下载
        // test08();

        // 测试-测试查询历史信息
//        test09();
    }

    /**
     * 测试内容: 生成 activiti 相关的表结构
     * 测试结果:
     */
    public static void test() {
        // 他会使用 classPath 下的 activiti.cfg.xml 中的配置类创建 ProcessEngine 对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        System.out.println(processEngine);


    }


    /**
     * 测试内容: 自定义的方式加载配置文件
     * 测试结果:
     */
    public void test01() {
        // 从资源目录下加载配置文件 创建 ProcessEngineConfiguration 对象
        ProcessEngineConfiguration processEngineConfigurationFromResource =
                ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
        // 再通过对象 获取 ProcessEngine
        ProcessEngine processEngine = processEngineConfigurationFromResource.buildProcessEngine();

    }


    /**
     * 测试内容: 实现文件的单个部署
     * 测试结果:
     */
    public static void test02() {

        // 获取 ProcessEngine 对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取 RepositoryService 进行部署
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 使用 RepositoryService 进行部署操作
        Deployment deploy = repositoryService.createDeployment()
                // 添加 bpmn 文件和 png 文件
                .addClasspathResource("bpmn/evection.bpmn")
                .addClasspathResource("bpmn/evection.png")
                .name("出差申请")
                .deploy();
        // 输出流程部署的信息
        System.out.println(deploy.getId());
        System.out.println(deploy.getName());
    }

    /**
     * 测试内容: 启动一个流程实例
     * 测试结果:
     */
    public static void test03() {
        // 1.创建 processEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 2.获取 RuntimeService 对象
        RuntimeService runtimeService = processEngine.getRuntimeService();
        // 3.根据流程定义的ID
        String id = "myProcess";
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(id);

        // 4.输出相关的流程实例信息
        System.out.println("流程定义的ID：" + processInstance.getProcessDefinitionId());
        System.out.println("流程实例的ID：" + processInstance.getId());
        System.out.println("当前活动的ID：" + processInstance.getActivityId());
    }


    /**
     * 测试内容: 任务查询
     * 测试结果:
     */
    public static void test04() {
        String assignee = "李四";
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 任务查询 需要一个 TaskService 对象
        TaskService taskService = processEngine.getTaskService();
        // 根据流程任务的 KEY 和 任务负责人 查询任务
        List<Task> process = taskService.createTaskQuery()
                // 需要查询的流程 KEY
                .processDefinitionKey("myProcess")
                // 查询当前流程的处理人
                .taskAssignee(assignee)
                .list();
        for (Task task : process) {
            System.out.println("流程实例ID：" + task.getProcessInstanceId());
            System.out.println("流程任务ID：" + task.getId());
            System.out.println("任务负责人：" + task.getAssignee());
            System.out.println("任务名称：" + task.getName());
        }
    }

    /**
     * 测试内容: 测试处理任务
     * 测试结果:
     */
    public static void test05() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

        TaskService taskService = processEngine.getTaskService();

        Task task = taskService.createTaskQuery()
                .processDefinitionKey("myProcess")
                .taskAssignee("张三")
                .singleResult();

        // 完成任务
        taskService.complete(task.getId());
    }

    /**
     * 测试内容: 查询流程的定义
     * 测试结果:
     */
    public static void test06() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

        RepositoryService repositoryService = processEngine.getRepositoryService();

        // 要获取一个 ProcessDefinitionQuery 流程定义信息查询对象
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();

        List<ProcessDefinition> process = processDefinitionQuery
                .processDefinitionKey("myProcess")  // 流程定义信息的 KEY
                .orderByProcessDefinitionVersion() //  按流程定义信息的版本排序
                .desc() // 倒序
                .list();

        // 打印输出

        for (ProcessDefinition processDefinition : process) {
            System.out.println("流程定义信息ID：" + processDefinition.getId());
            System.out.println("流程定义信息名称：" + processDefinition.getName());
            System.out.println("流程定义信息Key：" + processDefinition.getKey());
            System.out.println("流程定义类别：" + processDefinition.getCategory());
            System.out.println("流程部署的id：" + processDefinition.getDeploymentId());
            System.out.println("流程定义的版本：" + processDefinition.getVersion());
        }
    }

    /**
     * 测试内容: 测试删除部署的流程
     * 测试结果:
     */
    public static void test07() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 在删除流程时，当流程已经有了实例是无法删除的 --》 报错有外键管理
        repositoryService.deleteDeployment("7501");
        // 级联删除 就算有实例也可以删除，
        // repositoryService.deleteDeployment("10001", true);
    }

    /**
     * 测试内容: 资源文件下载
     * 测试结果:
     */
    public static void test08() throws Exception{
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 根据存储服务拿到查询器
        ProcessDefinition process = repositoryService.createProcessDefinitionQuery().
                processDefinitionKey("myProcess").singleResult();

        // 获取流程部署的id
        String deploymentId = process.getDeploymentId();
        // 通过 repository 对象的相关方法来读取图片信息和BPMN信息
        InputStream pngInput = repositoryService.getResourceAsStream(deploymentId, process.getDiagramResourceName());
        InputStream bpmnInput = repositoryService.getResourceAsStream(deploymentId, process.getResourceName());

        // 文件的保存
        File filePng = new File("d:/evection.png");
        File filebpmn = new File("d:/evection.bpmn");

        FileOutputStream pngOut = new FileOutputStream(filePng);
        FileOutputStream bpmnOut = new FileOutputStream(filebpmn);

        IOUtils.copy(bpmnInput, bpmnOut);
        IOUtils.copy(pngInput, pngOut);

        pngInput.close();
        bpmnInput.close();
        pngOut.close();
        bpmnOut.close();
    }


    /**
     * 测试内容: 查看流程历史信息
     * 测试结果:
     */
    public static void test09() throws Exception {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 拿到 历史服务 我们查询历史信息需要通过 HistoryService 来实现
        HistoryService historyService = processEngine.getHistoryService();
        // 获取 actinst 表的查询对象
        HistoricActivityInstanceQuery activityInstanceQuery = historyService.createHistoricActivityInstanceQuery();

        List<HistoricActivityInstance> historicActivityInstances = activityInstanceQuery.processDefinitionId("myProcess:2:10004")
                .orderByHistoricActivityInstanceStartTime().desc().list();

        for (HistoricActivityInstance activityInstance : historicActivityInstances) {
            System.out.println("活动ID" + activityInstance.getActivityId());
            System.out.println("活动名称" + activityInstance.getActivityName());
            System.out.println("活动类型" + activityInstance.getActivityType());
            System.out.println("活动处理人" + activityInstance.getAssignee());
            System.out.println("-----------------");
        }
    }
}
